<?php
// XML parser
// From http://PHP.com
// Basic error functions
class errorBase
{
    function backtrace($provideObject=false)
    {
        foreach(debug_backtrace($provideObject) as $row)
        {
            $args = $_SERVER['argv'];
            if($last!=$row['file'])
                echo "File: ".$row['file']."<br>\n'";

      $last=$row['file'];
            echo " Line: ".$row['line'].": ";
            if($row['class']!='')
                echo $row['class'].$row['type'].$row['function'];
            else
                echo $row['function'];

            echo "(";
            echo join("', '", $args);
            echo ")<br>\n";
        }
    }
    function error($msg,$fatal=false)
    {
        echo "<div align=\"center\"><font color=\"red\"><b>Error: $msg</b></font></div>";
        $last='';
        $this->backtrace();
        exit();
    }
    function fatalError($msg){return $this->error($msg,true);}
}

// Basic XML parser with all call-backs abstracted
class xmlBase  extends errorBase
{

    // Valuable resource
    var $_p;

    // Constructor/destructor
    function xmlBase($ns=false, $encoding=null, $separator=null)
    {
            $this->_p = $ns
                                                ?
                                                xml_parser_create_ns($encoding,$separator)
                                                :
                                                xml_parser_create($encoding);

            xml_parser_set_option($this->_p, XML_OPTION_CASE_FOLDING, 0);
            xml_set_object($this->_p, $this);
            xml_set_default_handler($this->_p,"_default");
            xml_set_element_handler($this->_p, "_tagOpen", "_tagClose");
            xml_set_character_data_handler($this->_p, "_cdata");
            xml_set_start_namespace_decl_handler($this->_p,"_nsStart");
            xml_set_end_namespace_decl_handler($this->_p,"_nsEnd");
            xml_set_external_entity_ref_handler($this->_p,"_entityRef");
            xml_set_processing_instruction_handler($this->_p,"_pi");
            xml_set_notation_decl_handler($this->_p,"_notation");
            xml_set_unparsed_entity_decl_handler($this->_p,"_unparsedEntity");
    } 
    function _xmlBase()
    {
        xml_parser_free($this->_p);
        $this->_p=null;
    }
   
    // All private abstract methods - override these
    function _default($parser,$data) {}
    function _tagOpen($parser,$tag, $attribs) { }
    function _tagClose($parser,$tag) {}
    function _cdata($parser,$data) {}
    function _nsStart($parser,$userData, $prefix, $uri='') {}
    function _nsEnd($parser,$userData,$prefix) {}
    function _entityRef($parser,
                                  $openEntityNames,
                                                                $base,
                                                                $systemID,
                                                                $publicID)                    {}
    function _pi($parser,$target,$data){}
    function _notation($parser,
                                  $notationName,
                                                                $base,
                                                                $systemID,
                                                                $publicID)                    {}
    function _unparsedEntity($parser,
                                  $entityName,
                                                                $base,
                                                                $systemID,
                                                                $publicID,
                                                                $notationName){}

    function _parse($data,$final=false)
    {
        if(!xml_parse($this->_p,$data,$final))
        {
            echo $data.'<br />';
            $this->fatalError(sprintf('XML error %d:"%s" at line %d column %d byte %d',
            xml_get_error_code($this->_p),
            xml_error_string($this->_p),
            xml_get_current_line_number($this->_p),
            xml_get_current_column_number($this->_p),
            xml_get_current_byte_index($this->_p)));
        }
    }
   
    // All the public functions you're meant to not override
    function setOption($option,$value)    {return xml_parser_set_option($this->_p,$option,$value);}
    function getOption($option)              {return xml_parser_get_option($this->_p,$option);}
    function parseFile($file)
    {
        if(($f=fopen($file,'r'))!=null)
        {
            while(!feof($f))
                $this->parse(fgets($f, 4096));
            $this->parseEnd();
        }
        else
            $this->fatalError("Unable to open file $file");
    }
    function parseEnd()
    {
        $this->_parse(null,true);
    }
    function parse($data)
    {
	$data = str_replace('<?=', '<?ret ', $data);
	$data = str_replace('<?:', '<?php ', $data);
        $this->_parse($data);
    }
}
?>
